package cn.zwk.service;

import cn.zwk.config.TemplateConfig;
import cn.zwk.entity.AbstractItem;
import cn.zwk.entity.MetricList;
import cn.zwk.entity.Snapshoot;
import cn.zwk.handler.*;
import cn.zwk.resolver.MetricListText;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;

@Slf4j
@Component
public class RunServer implements CommandLineRunner {

    @Autowired
    private TemplateConfig templateConfig;
    
    @Autowired
    private ProgressService progressService;
    
    @Autowired
    private HttpSenderService httpSenderService;

    private final Map<String, MetricHandler> handlerMap = new HashMap<>();

    public RunServer() {
        handlerMap.put("gauge", new GaugeHandler());
        handlerMap.put("counter", new CounterHandler());
        handlerMap.put("histogram", new HistogramHandler());
        handlerMap.put("summary", new SummaryHandler());
    }

    @Override
    public void run(String... args) throws Exception {
        log.info("开始启动虚拟线程数据生成和发送服务...");
        
        // 验证配置
        if (templateConfig == null) {
            log.error("配置文件未加载，请检查application.yml文件");
            return;
        }
        
        if (templateConfig.getTemplates() == null || templateConfig.getTemplates().isEmpty()) {
            log.error("未找到模板配置，请检查application.yml中的templates配置");
            return;
        }
        
        if (templateConfig.getGlobal() == null || templateConfig.getGlobal().getRemoteUrl() == null) {
            log.error("未找到全局配置，请检查application.yml中的global配置");
            return;
        }
        
        log.info("配置验证成功，远程URL: {}", templateConfig.getGlobal().getRemoteUrl());
        
        // 启动进度报告
        progressService.startProgressReporting();
        
        // 使用虚拟线程执行器
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            List<CompletableFuture<Void>> futures = new ArrayList<>();
            // 为每个模板的每个副本创建一个虚拟线程
            for (TemplateConfig.Template template : templateConfig.getTemplates()) {
                if (template.getReplicas() <= 0) {
                    log.warn("模板 {} 没有配置副本数量或副本数量为0，跳过", template.getName());
                    continue;
                }
                
                for (int i = 1; i <= template.getReplicas(); i++) {
                    String hostname = template.getName() + "-" + String.format("%03d", i);
                    
                    // 初始化进度跟踪
                    progressService.initProgress(hostname, template.getCount());
                    
                    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                        try {
                            processTemplateHost(template, hostname);
                        } catch (Exception e) {
                            log.error("处理模板 {} 主机 {} 时发生错误: {}", 
                                    template.getName(), hostname, e.getMessage(), e);
                        }
                    }, executor);
                    futures.add(future);
                }
            }
            
            log.info("已启动 {} 个虚拟线程", futures.size());
            
            // 等待所有任务完成
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        }
        
        log.info("所有数据生成和发送任务已完成");
    }
    
    private void processTemplateHost(TemplateConfig.Template template, String host) throws Exception {
        log.info("开始处理模板 {} 主机 {}", template.getName(), host);
        
        // 读取模板文件
        String input = readFileAsString(template.getPath());
        if (input == null) {
            log.error("无法读取模板文件: {}", template.getPath());
            return;
        }
        
        List<String> list = split(input)
                .stream()
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .toList();
        
        List<MetricListText> textList = buildText(list);
        
        // 为每个host创建一个Snapshoot，并嵌入interval_ms
        Snapshoot snapshoot = Snapshoot.build(textList, template.getStartTimestamp(), host, template.getIntervalMs());
        
        // 按指定次数执行next和发送
        for (int i = 0; i < template.getCount(); i++) {
            if (i > 0) {
                // 调用next方法更新数据和时间戳
                next(snapshoot);
            }
            
            // 发送数据
            String data = snapshoot.toString();
            
            // Debug输出快照的值
            log.debug("准备发送数据 - 模板: {}, 主机: {}, 第 {}/{} 次:\n{}", 
                    template.getName(), host, i + 1, template.getCount(), data);
            
            httpSenderService.sendData(templateConfig.getGlobal().getRemoteUrl(), data, 
                    templateConfig.getGlobal().isWaitResponse());
            
            // 更新进度
            progressService.updateProgress(host);
            
            log.info("已发送数据 - 模板: {}, 主机: {}, 第 {}/{} 次", 
                    template.getName(), host, i + 1, template.getCount());
        }
        
        log.info("完成处理模板 {} 主机 {}", template.getName(), host);
    }

    public void next(Snapshoot snapshoot) {
        // 更新时间戳：根据配置的间隔增长
        snapshoot.setTimestamp(snapshoot.getTimestamp() + snapshoot.getInterval_ms());

        if (CollectionUtils.isEmpty(snapshoot.getMetricList())) return;
        // 更新所有指标数据
        for (MetricList list : snapshoot.getMetricList()) {
            if (list.getItems() == null) continue;

            for (AbstractItem item : list.getItems()) {
                // 根据指标类型调用对应的handler来更新数据
                String type = list.getType();
                MetricHandler handler = handlerMap.get(type);
                if (handler != null) {
                    handler.next(item);
                }

            }
        }
    }

    public static String readFileAsString(String filePath) {
        try {
            return Files.readString(Path.of(filePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public List<String> split(String input) {
        if (input == null || input.isEmpty()) {
            return List.of();
        }
        return List.of(input.split("(?=# HELP)"));
    }

    public List<MetricListText> buildText(List<String> strings) {
        if (strings == null || strings.isEmpty()) {
            return List.of();
        }
        return strings.stream()
                .map(s -> {
                    String[] lines = s.split("\n");
                    if (lines.length < 2) return null;
                    int i = lines[0].startsWith("# TYPE") ? 0 : 1;
                    String[] parts = lines[i].split("\\s+");
                    String name = parts[2];
                    String type = parts[3];
                    MetricHandler metricHandler = handlerMap.get(type);
                    return metricHandler == null ? null : new MetricListText(name, type, i + 1, s, metricHandler);
                })
                .filter(Objects::nonNull)
                .toList();
    }
}
